//
//  ChatupApp.swift
//  Chatup
//
//  Created by op on 2023/10/15.
//

import Alamofire
import FBSDKCoreKit
import FirebaseAnalytics
import FirebaseAuth
import FirebaseCore
import FirebaseFirestore
import SwiftUI
import SwiftyStoreKit

@main
struct ChatupApp: App {
    @State private var showMainApp = false
    @AppStorage("kHasSeenGuide") private var hasSeenGuide: Bool = false
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
//    @State private var hasSeenGuide: Bool = false
    @State private var currentRoleIndex = 0
    
    var body: some Scene {
        WindowGroup {
            if showMainApp {
                if hasSeenGuide {
                    ContentView()
                        .onAppear {
                            getConfig()
                        }
                } else {
                    GuideView(showGuidView: $hasSeenGuide)
                        .onAppear {
                            initDb()
                        }
                }
            } else {
                SplashView()
                    .onAppear {
                        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
                            withAnimation {
                                showMainApp = true
                            }
                        }
                    }
            }
        }
    }
    
    private func getConfig() {
        if let uuid = UserDefaults.standard.string(forKey: "uuid"), uuid.count > 0 {
        } else {
            let randomID = randomString(length: 16)
            UserDefaults.standard.setValue(randomID, forKey: "uuid")
            UserDefaults.standard.synchronize()
        }
        
        RequestManager.shared.getWith("https://backend.aichattings.com/api/role/list") { json, _ in
            if let data = json, let dic = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
                Config.shared.toModel(dic: dic)
            }
        } fail: { _, _, _ in
        }
    }
    
    func randomString(length: Int) -> String {
        let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
        return String((0 ..< length).map { _ in letters.randomElement()! })
    }

    
    
    private func initDb() {
        guard !UserDefaults.standard.bool(forKey: "kHasInitDatabase") else{return}
        
        let roleModels = [
            RoleModel(type: RoleModelType.bot.rawValue, questionTemplate: "", icon: "icon_robot", greeting: "Hello! How can i assist you today? I'm here to help you with any questions or tasks you may have", desc: "chat_ai_assistant", lastTime: kCurentTimeInt(), name: "Chris", serverId: 0, category: "", images: [], imageIndex: 1),
            RoleModel(type: RoleModelType.elon.rawValue, questionTemplate: "", icon: "ai-character-elon-musk", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Elon Musk", serverId: 1, category: "Celebrity", images: [], imageIndex: 1),
            RoleModel(type: RoleModelType.bella.rawValue, questionTemplate: "", icon: "ai-character-isabella", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Isabella", serverId: 2, category: "AI Girlfriend", images: ["role2-isabella-01","role2-isabella-02","role2-isabella-03","role2-isabella-04"], imageIndex: 1),
            RoleModel(type: RoleModelType.jeans.rawValue, questionTemplate: "", icon: "ai-character-yuki-tanaka", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Yuki Tanaka", serverId: 3, category: "AI Girlfriend", images: ["role3-yuki-tanaka-isbella-01","role3-yuki-tanaka-isbella-02","role3-yuki-tanaka-isbella-03","role3-yuki-tanaka-isbella-04"], imageIndex: 1),
            RoleModel(type: RoleModelType.mia.rawValue, questionTemplate: "", icon: "ai-character-mia-rivera", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Mia Rivera", serverId: 4, category: "AI Girlfriend", images: ["role4-mia-rivera-01","role4-mia-rivera-02","role4-mia-rivera-03","role4-mia-rivera-04"], imageIndex: 1),
            RoleModel(type: RoleModelType.aria.rawValue, questionTemplate: "", icon: "ai-character-aira-bennett", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Aria Bennett", serverId: 5, category: "AI Girlfriend", images: ["role5-aira-bennett-01","role5-aira-bennett-02","role5-aira-bennett-03","role5-aira-bennett-04"], imageIndex: 1),
            RoleModel(type: RoleModelType.emily.rawValue, questionTemplate: "", icon: "ai-character-emily-parker", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Emily Parker", serverId: 6, category: "AI Girlfriend", images: ["role6-emily-parker-01","role6-emily-parker-02","role6-emily-parker-03","role6-emily-parker-04"], imageIndex: 1),
            RoleModel(type: RoleModelType.kanye.rawValue, questionTemplate: "", icon: "ai-character-kanye-west", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Kanye West", serverId: 7, category: "Celebrity", images: [], imageIndex: 1),
            RoleModel(type: RoleModelType.ariana.rawValue, questionTemplate: "", icon: "ai-character-ariana-grande", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Ariana Grande", serverId: 8, category: "Celebrity", images: [], imageIndex: 1),
            RoleModel(type: RoleModelType.im.rawValue, questionTemplate: "", icon: "ai-character-im-na-yeon", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Im Na-yeon", serverId: 9, category: "Celebrity", images: [], imageIndex: 1),
            RoleModel(type: RoleModelType.cristiano.rawValue, questionTemplate: "", icon: "ai-character-cristiano-ronaldo", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Cristiano Ronaldo", serverId: 10, category: "Celebrity", images: [], imageIndex: 1),
            RoleModel(type: RoleModelType.naruto.rawValue, questionTemplate: "", icon: "ai-character-naruto", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Naruto", serverId: 11, category: "Anime", images: [], imageIndex: 1),
            RoleModel(type: RoleModelType.monkey.rawValue, questionTemplate: "", icon: "ai-character-luffy", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Monkey D. Luffy", serverId: 12, category: "Anime", images: [], imageIndex: 1),
            RoleModel(type: RoleModelType.satoru.rawValue, questionTemplate: "", icon: "ai-character-satoru-gojo", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Satoru Gojo", serverId: 13, category: "Anime", images: [], imageIndex: 1),
            RoleModel(type: RoleModelType.nezuko.rawValue, questionTemplate: "", icon: "ai-character-nezuko-kamado", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Nezuko Kamado", serverId: 14, category: "Anime", images: [], imageIndex: 1),
            RoleModel(type: RoleModelType.yor.rawValue, questionTemplate: "", icon: "ai-character-yor-briar", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Yor Briar", serverId: 15, category: "Anime", images: [], imageIndex: 1),
            RoleModel(type: RoleModelType.ganyu.rawValue, questionTemplate: "", icon: "ai-character-ganyu", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Ganyu", serverId: 16, category: "Game", images: [], imageIndex: 1),
            RoleModel(type: RoleModelType.mario.rawValue, questionTemplate: "", icon: "ai-character-marios", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Mario", serverId: 17, category: "Game", images: [], imageIndex: 1),
            RoleModel(type: RoleModelType.bb.rawValue, questionTemplate: "", icon: "ai-character-2b", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "2B", serverId: 18, category: "Game", images: [], imageIndex: 1),
            RoleModel(type: RoleModelType.juri.rawValue, questionTemplate: "", icon: "ai-character-juri-han", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Juri Han", serverId: 19, category: "Game", images: [], imageIndex: 1),
            RoleModel(type: RoleModelType.link.rawValue, questionTemplate: "", icon: "ai-character-link", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Link", serverId: 20, category: "Game", images: [], imageIndex: 1),
            RoleModel(type: RoleModelType.matthew.rawValue, questionTemplate: "", icon: "ai-character-matthew-collins", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Matthew Collins", serverId: 21, category: "AI Boyfriend", images: ["role21-matthew-collins-01","role21-matthew-collins-02","role21-matthew-collins-03","role21-matthew-collins-04"], imageIndex: 1),
            RoleModel(type: RoleModelType.liam.rawValue, questionTemplate: "", icon: "ai-character-liam-brooks", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Liam Brooks", serverId: 22, category: "AI Boyfriend", images: ["role22-liam-brooks-01","role22-liam-brooks-02","role22-liam-brooks-03","role22-liam-brooks-04"], imageIndex: 1),
            RoleModel(type: RoleModelType.miller.rawValue, questionTemplate: "", icon: "ai-character-miller", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Miller", serverId: 23, category: "AI Boyfriend", images: ["role23-miller-01","role23-miller-02","role23-miller-03","role23-miller-04"], imageIndex: 1),
            RoleModel(type: RoleModelType.andrew.rawValue, questionTemplate: "", icon: "ai-character-andrew", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Andrew", serverId: 24, category: "AI Boyfriend", images: ["role24-andrew-01","role24-andrew-02","role24-andrew-03","role24-andrew-04"], imageIndex: 1),
            RoleModel(type: RoleModelType.evan.rawValue, questionTemplate: "", icon: "ai-character-evan", greeting: nil, desc: nil, lastTime: kCurentTimeInt(), name: "Evan", serverId: 25, category: "AI Boyfriend", images: ["role25-evan-01","role25-evan-02","role25-evan-03","role25-evan-04"], imageIndex: 1),
        ]
        guard currentRoleIndex < roleModels.count else {
            UserDefaults.standard.setValue(true, forKey: "kHasInitDatabase")
            UserDefaults.standard.synchronize()
            return
        }

        let roleModel = roleModels[currentRoleIndex]
        RoleDataManager.share.saveRole(role: roleModel)
                
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
            self.currentRoleIndex += 1
            self.initDb()
        }
    }

    
    func kCurentTimeInt() -> Int64 {
        return Int64(Date().timeIntervalSince1970 * 1000)
    }
}

class AppDelegate: NSObject, UIApplicationDelegate {
    private static var _shareInstance: AppDelegate?
    private let queue = DispatchQueue(label: "reachability_queue")
    func application(
        _ app: UIApplication,
        open url: URL,
        options: [UIApplication.OpenURLOptionsKey: Any] = [:]
    ) -> Bool {
        ApplicationDelegate.shared.application(
            app,
            open: url,
            sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,
            annotation: options[UIApplication.OpenURLOptionsKey.annotation]
        )
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
        FirebaseApp.configure()
        ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
        Settings.shared.isAdvertiserTrackingEnabled = true
        
        SwiftyStoreKit.completeTransactions(atomically: true) { purchases in
            for purchase in purchases {
                switch purchase.transaction.transactionState {
                case .purchased, .restored:
                    if purchase.needsFinishTransaction {
                        SwiftyStoreKit.finishTransaction(purchase.transaction)
                    }
                case .failed, .purchasing, .deferred:
                    break // do nothing
                @unknown default: break
                }
            }
            AppVipManager.shared.checkVip()
        }
        AppVipManager.shared.checkVip()
        AppDelegate._shareInstance = self
        
        if UserDefaults.standard.bool(forKey: "kHasSeenGuide") && !UserDefaults.standard.bool(forKey: "kWhetherVip") {
            DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
                let viewControllerToPresent = UIHostingController(rootView: VipView(viewModel: .init(from: "start")))
                viewControllerToPresent.modalPresentationStyle = .fullScreen
                AppDelegate.shareInstance()?.getCurrentVC()?.present(viewControllerToPresent, animated: true)
            }
        }
        
        if let currentLocale = Locale.current.regionCode {
            Analytics.setUserProperty(currentLocale, forName: "country")
        }
        
        let preferredLanguage = Locale.preferredLanguages.first ?? "unknow"
        Analytics.setUserProperty(preferredLanguage, forName: "language")
        
        var systemInfo = utsname()
        uname(&systemInfo)
        let machineMirror = Mirror(reflecting: systemInfo.machine)
        let identifier = machineMirror.children.reduce("") { identifier, element in
            guard let value = element.value as? Int8, value != 0 else { return identifier }
            return identifier + String(UnicodeScalar(UInt8(value)))
        }
        Analytics.setUserProperty(identifier, forName: "device")
        
        let systemVersion = ProcessInfo.processInfo.operatingSystemVersion
        Analytics.setUserProperty("\(systemVersion.majorVersion).\(systemVersion.minorVersion).\(systemVersion.patchVersion)", forName: "os_version")
            
        NetworkReachabilityManager()?.startListening(onQueue: queue, onUpdatePerforming: { [weak self] status in
            switch status {
            case .reachable(let type):
                Analytics.setUserProperty("\(type)", forName: "network_status")
            default:
                print("")
            }
        })
        let userDefaults = UserDefaults.standard
        let isOldUser = userDefaults.bool(forKey: "isOldUser")
        if !isOldUser {
            Analytics.setUserProperty("\(!isOldUser)", forName: "new_users")
            userDefaults.set(true, forKey: "isOldUser")
        } else {
            Analytics.setUserProperty("\(!isOldUser)", forName: "new_users")
        }
        
        var subStatus = userDefaults.string(forKey: "kVipProductId")
        if subStatus == nil || subStatus == "" {
            subStatus = "none"
        }
        Analytics.setUserProperty(subStatus, forName: "sub_status")
        
        return true
    }
    
    static func shareInstance() -> AppDelegate? {
        return AppDelegate._shareInstance
    }
    
    public func getCurrentVC() -> UIViewController? {
        return UIViewController.topViewController()
    }
}

extension UIViewController {
    public class func topViewController() -> UIViewController? {
        var window = UIApplication.shared.windows.filter { $0.isKeyWindow }.first
        // 判断是否为当前显示的window
        if window?.windowLevel != .normal {
            let windows = UIApplication.shared.windows
            for tWindow in windows {
                if tWindow.windowLevel == .normal {
                    window = tWindow
                    break
                }
            }
        }
        let vc = window?.rootViewController
        return getTopVC(vc: vc)
    }
    
    func presentFullStyle(_ viewControllerToPresent: UIViewController, animation: Bool = true) {
        viewControllerToPresent.modalPresentationStyle = .fullScreen
        present(viewControllerToPresent, animated: animation, completion: nil)
    }
    
    private class func getTopVC(vc: UIViewController?) -> UIViewController? {
        guard vc != nil else {
            debugPrint("找不到顶层控制器...")
            return nil
        }
        if let presentVc = vc?.presentedViewController {
            // modal出来的控制器
            return getTopVC(vc: presentVc)
        } else if let tabVc = vc as? UITabBarController {
            if let selectedVc = tabVc.selectedViewController {
                return getTopVC(vc: selectedVc)
            }
            return nil
        } else if let navVc = vc as? UINavigationController {
            return getTopVC(vc: navVc.visibleViewController)
        } else {
            // 返回顶层控制器
            return vc
        }
    }
}

